#include <iostream>
#include <cstring>
#include <cstdlib>
#include <sys/epoll.h>

using std::cout;
using std::cerr;
using std::endl;

#define SIZE 128
#define EPOLL_CREATE_ERR 4
#define EPOLL_CTL_ADD_ERR 5
#define EPOLL_WAIT_ERR 6
#define EPOLL_CTL_MOD_ERR 7

class Epoll
{
public:
    static int CreateEpoll() // 创建epoll模型
    {
        int epfd = epoll_create(SIZE);
        if (epfd < 0)
        {
            cerr << "epoll create error: " << strerror(errno) << endl;
            exit(EPOLL_CREATE_ERR);
        }
        return epfd;
    }

    static void AddEvent(int epfd, int fd, uint32_t eventType) // 添加fd到epoll模型进行特定事件监听
    {
        epoll_event evt;
        evt.events = eventType;
        evt.data.fd = fd;

        int n = epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &evt);
        if (n < 0)
        {
            cout << "epoll_ctl add enent error: " << strerror(errno) << endl;
            exit(EPOLL_CTL_ADD_ERR);
        }
    }

    static bool ModEventState(int epfd, int fd, int eventType) // 更改epoll模型中RB_Tree节点所存储的事件类型
    {
        epoll_event evt;
        evt.events = eventType;
        evt.data.fd = fd;

        int n = epoll_ctl(epfd, EPOLL_CTL_MOD, fd, &evt);
        if (n < 0)
        {
            cout << "epoll_ctl modify enent error: " << strerror(errno) << endl;
            return false;
        }
        return true;
    }

    static bool DelEvent(int epfd, int fd) // 删除epoll模型中RB_Tree存储的节点 -- 去除监听
    {
        int n = epoll_ctl(epfd, EPOLL_CTL_DEL, fd, nullptr);
        if (n < 0)
        {
            cout << "epoll_ctl delete enent error: " << strerror(errno) << endl;
            return false;
        }
        return true;
    }

    static int LoopOnce(int epfd, epoll_event *events, int maxevents) // 获取底层已经就绪的事件到events
    {
        int timeout = -1; // 单位: 毫秒 --> >0 非阻塞、==0阻塞、<0永久阻塞
        int n = epoll_wait(epfd, events, maxevents, timeout);
        if (n < 0)
        {
            cout << "epoll_wait error: " << strerror(errno) << endl;
            exit(EPOLL_WAIT_ERR);
        }
        return n;
    }
};